1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21
22 import com.google.common.annotations.Beta;
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.base.Function;
25 import com.google.common.base.Supplier;
26
27 import java.io.Serializable;
28 import java.util.Comparator;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.NoSuchElementException;
32 import java.util.Set;
33 import java.util.SortedMap;
34 import java.util.SortedSet;
35 import java.util.TreeMap;
36
37 import javax.annotation.Nullable;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 @GwtCompatible(serializable = true)
78 @Beta
79 public class TreeBasedTable<R, C, V> extends StandardRowSortedTable<R, C, V> {
80 private final Comparator<? super C> columnComparator;
81
82 private static class Factory<C, V>
83 implements Supplier<TreeMap<C, V>>, Serializable {
84 final Comparator<? super C> comparator;
85 Factory(Comparator<? super C> comparator) {
86 this.comparator = comparator;
87 }
88 @Override
89 public TreeMap<C, V> get() {
90 return new TreeMap<C, V>(comparator);
91 }
92 private static final long serialVersionUID = 0;
93 }
94
95
96
97
98
99
100
101
102
103
104 public static <R extends Comparable, C extends Comparable, V>
105 TreeBasedTable<R, C, V> create() {
106 return new TreeBasedTable<R, C, V>(Ordering.natural(),
107 Ordering.natural());
108 }
109
110
111
112
113
114
115
116
117 public static <R, C, V> TreeBasedTable<R, C, V> create(
118 Comparator<? super R> rowComparator,
119 Comparator<? super C> columnComparator) {
120 checkNotNull(rowComparator);
121 checkNotNull(columnComparator);
122 return new TreeBasedTable<R, C, V>(rowComparator, columnComparator);
123 }
124
125
126
127
128
129 public static <R, C, V> TreeBasedTable<R, C, V> create(
130 TreeBasedTable<R, C, ? extends V> table) {
131 TreeBasedTable<R, C, V> result
132 = new TreeBasedTable<R, C, V>(
133 table.rowComparator(), table.columnComparator());
134 result.putAll(table);
135 return result;
136 }
137
138 TreeBasedTable(Comparator<? super R> rowComparator,
139 Comparator<? super C> columnComparator) {
140 super(new TreeMap<R, Map<C, V>>(rowComparator),
141 new Factory<C, V>(columnComparator));
142 this.columnComparator = columnComparator;
143 }
144
145
146
147
148
149
150
151 public Comparator<? super R> rowComparator() {
152 return rowKeySet().comparator();
153 }
154
155
156
157
158
159 public Comparator<? super C> columnComparator() {
160 return columnComparator;
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175 @Override
176 public SortedMap<C, V> row(R rowKey) {
177 return new TreeRow(rowKey);
178 }
179
180 private class TreeRow extends Row implements SortedMap<C, V> {
181 @Nullable final C lowerBound;
182 @Nullable final C upperBound;
183
184 TreeRow(R rowKey) {
185 this(rowKey, null, null);
186 }
187
188 TreeRow(R rowKey, @Nullable C lowerBound, @Nullable C upperBound) {
189 super(rowKey);
190 this.lowerBound = lowerBound;
191 this.upperBound = upperBound;
192 checkArgument(lowerBound == null || upperBound == null
193 || compare(lowerBound, upperBound) <= 0);
194 }
195
196 @Override public SortedSet<C> keySet() {
197 return new Maps.SortedKeySet<C, V>(this);
198 }
199
200 @Override public Comparator<? super C> comparator() {
201 return columnComparator();
202 }
203
204 int compare(Object a, Object b) {
205
206 @SuppressWarnings({"rawtypes", "unchecked"})
207 Comparator<Object> cmp = (Comparator) comparator();
208 return cmp.compare(a, b);
209 }
210
211 boolean rangeContains(@Nullable Object o) {
212 return o != null && (lowerBound == null || compare(lowerBound, o) <= 0)
213 && (upperBound == null || compare(upperBound, o) > 0);
214 }
215
216 @Override public SortedMap<C, V> subMap(C fromKey, C toKey) {
217 checkArgument(rangeContains(checkNotNull(fromKey))
218 && rangeContains(checkNotNull(toKey)));
219 return new TreeRow(rowKey, fromKey, toKey);
220 }
221
222 @Override public SortedMap<C, V> headMap(C toKey) {
223 checkArgument(rangeContains(checkNotNull(toKey)));
224 return new TreeRow(rowKey, lowerBound, toKey);
225 }
226
227 @Override public SortedMap<C, V> tailMap(C fromKey) {
228 checkArgument(rangeContains(checkNotNull(fromKey)));
229 return new TreeRow(rowKey, fromKey, upperBound);
230 }
231
232 @Override public C firstKey() {
233 SortedMap<C, V> backing = backingRowMap();
234 if (backing == null) {
235 throw new NoSuchElementException();
236 }
237 return backingRowMap().firstKey();
238 }
239
240 @Override public C lastKey() {
241 SortedMap<C, V> backing = backingRowMap();
242 if (backing == null) {
243 throw new NoSuchElementException();
244 }
245 return backingRowMap().lastKey();
246 }
247
248 transient SortedMap<C, V> wholeRow;
249
250
251
252
253
254 SortedMap<C, V> wholeRow() {
255 if (wholeRow == null
256 || (wholeRow.isEmpty() && backingMap.containsKey(rowKey))) {
257 wholeRow = (SortedMap<C, V>) backingMap.get(rowKey);
258 }
259 return wholeRow;
260 }
261
262 @Override
263 SortedMap<C, V> backingRowMap() {
264 return (SortedMap<C, V>) super.backingRowMap();
265 }
266
267 @Override
268 SortedMap<C, V> computeBackingRowMap() {
269 SortedMap<C, V> map = wholeRow();
270 if (map != null) {
271 if (lowerBound != null) {
272 map = map.tailMap(lowerBound);
273 }
274 if (upperBound != null) {
275 map = map.headMap(upperBound);
276 }
277 return map;
278 }
279 return null;
280 }
281
282 @Override
283 void maintainEmptyInvariant() {
284 if (wholeRow() != null && wholeRow.isEmpty()) {
285 backingMap.remove(rowKey);
286 wholeRow = null;
287 backingRowMap = null;
288 }
289 }
290
291 @Override public boolean containsKey(Object key) {
292 return rangeContains(key) && super.containsKey(key);
293 }
294
295 @Override public V put(C key, V value) {
296 checkArgument(rangeContains(checkNotNull(key)));
297 return super.put(key, value);
298 }
299 }
300
301
302
303 @Override public SortedSet<R> rowKeySet() {
304 return super.rowKeySet();
305 }
306
307 @Override public SortedMap<R, Map<C, V>> rowMap() {
308 return super.rowMap();
309 }
310
311
312
313
314
315 @Override
316 Iterator<C> createColumnKeyIterator() {
317 final Comparator<? super C> comparator = columnComparator();
318
319 final Iterator<C> merged =
320 Iterators.mergeSorted(Iterables.transform(backingMap.values(),
321 new Function<Map<C, V>, Iterator<C>>() {
322 @Override
323 public Iterator<C> apply(Map<C, V> input) {
324 return input.keySet().iterator();
325 }
326 }), comparator);
327
328 return new AbstractIterator<C>() {
329 C lastValue;
330
331 @Override
332 protected C computeNext() {
333 while (merged.hasNext()) {
334 C next = merged.next();
335 boolean duplicate =
336 lastValue != null && comparator.compare(next, lastValue) == 0;
337
338
339 if (!duplicate) {
340 lastValue = next;
341 return lastValue;
342 }
343 }
344
345 lastValue = null;
346 return endOfData();
347 }
348 };
349 }
350
351 private static final long serialVersionUID = 0;
352 }